﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Pixysoft.Collections
{
    public class ListQueue<T>
    {
        private readonly ReaderWriterLock locker = new ReaderWriterLock();//

        ListQueueElement header = null;
        ListQueueElement footer = null;

        public bool Remove(T item)
        {
            if (item == null)
                throw new VerificationFailedException("missing item");

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                ListQueueElement element = header;

                while (element != null)
                {
                    if (element.GetValue().Equals(item))
                    {
                        element.Remove();

                        return true;
                    }

                    element = element.Child;
                }

                return false;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        public int Count
        {
            get
            {
                locker.AcquireReaderLock(Timeout.Infinite);

                try
                {
                    if (this.header == null)
                        return 0;

                    return header.Size();
                }
                finally
                {
                    locker.ReleaseReaderLock();
                }
            }
        }

        public void Clear()
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                this.header = null;
                this.footer = null;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public bool Contains(T item)
        {
            if (item == null)
                throw new VerificationFailedException("missing item");

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                ListQueueElement element = header;

                while (element != null)
                {
                    if (element.GetValue().Equals(item))
                        return true;

                    element = element.Child;
                }

                return false;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        public T Dequeue()
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (this.header == null)
                    return default(T);

                ListQueueElement element = this.header;

                this.header = element.Child;

                element.Remove();

                return element.GetValue();
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public void Enqueue(T item)
        {
            if (item == null)
                throw new VerificationFailedException("missing item");

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                ListQueueElement element = new ListQueueElement(item);

                if (header == null)
                {
                    header = element;
                    footer = element;
                }
                else
                {
                    footer.Append(element);
                    this.footer = element;
                }
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        public T Peek()
        {
            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (header == null)
                    return default(T);

                return header.GetValue();
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        public T[] ToArray()
        {
            List<T> list = new List<T>();

            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                ListQueueElement element = header;

                while (element != null)
                {
                    list.Add(element.GetValue());

                    element = element.Child;
                }

                return list.ToArray();
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        class ListQueueElement
        {
            private ListQueueElement parent = null;
            private ListQueueElement child = null;
            private T value;

            public ListQueueElement(T value)
            {
                this.value = value;
            }

            /*
             * current element is header
             */
            public bool IsHeader()
            {
                return this.Parent == null;
            }

            /*
             * current element is footer
             */
            public bool IsFooter()
            {
                return this.Child == null;
            }

            /*
             * get parent element.
             */
            public ListQueueElement Parent
            {
                get
                {
                    return parent;
                }
                set
                {
                    this.parent = value;
                }
            }

            /*
             * get child element.
             */
            public ListQueueElement Child
            {
                get
                {
                    return child;
                }
                set
                {
                    this.child = value;
                }
            }

            /*
             * get size of queue
             */
            public int Size()
            {
                ListQueueElement element = GetHeader();
                int counter = 0;
                while (element != null)
                {
                    counter++;
                    element = element.Child;
                }
                return counter;
            }

            /*
             * get value
             */
            public T GetValue()
            {
                return value;
            }

            /*
             * set value
             */
            public void SetValue(T value)
            {
                this.value = value;
            }

            /*
             * get header, return this if is header
             */
            public ListQueueElement GetHeader()
            {
                if (parent != null)
                    return parent.GetHeader();

                return this;
            }

            /*
             * get footer, return this if is footer
             */
            public ListQueueElement GetFooter()
            {
                if (child != null)
                    return child.GetFooter();

                return this;
            }

            /*
             * insert element to the front of current element of link
             */
            public void Insert(ListQueueElement element)
            {
                // parent - (+element) this - child

                if (this.Parent != null)
                    this.Parent.Child = element;

                element.Parent = this.Parent;

                this.Parent = element;

                element.Child = this;
            }

            /*
             * append element as the child of current element of link
             */
            public void Append(ListQueueElement element)
            {
                // parent - this (+element) - child

                if (this.Child != null)
                    this.Child.Parent = element;

                element.Child = this.Child;

                element.Parent = this;

                this.Child = element;
            }

            /*
             * remove myself from link
             */
            public void Remove()
            {
                Remove(this);
            }

            /*
             * remove the element from link
             */
            public void Remove(ListQueueElement element)
            {
                // parent - element - child

                if (element.Parent != null)
                    element.Parent.Child = element.Child;

                if (element.Child != null)
                    element.Child.Parent = element.Parent;

                element.Parent = null;

                element.Child = null;
            }

            /*
             * to string
             */
            public override string ToString()
            {
                StringBuilder buffer = new StringBuilder();
                ListQueueElement element = this.GetHeader();
                while (element != null)
                {
                    buffer.Append("V:" + element.value + "  ");
                    element = element.Child;
                }
                return buffer.ToString();
            }

        }
    }
}
